package me.ingxin.android.router.compiler.processor

import com.squareup.kotlinpoet.*
import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
import me.ingxin.android.router.annotaions.App
import me.ingxin.android.router.annotaions.compiler.LExtInfo
import me.ingxin.android.router.annotaions.compiler.LInterceptor
import me.ingxin.android.router.annotaions.compiler.LInterceptorIndex
import me.ingxin.android.router.compiler.util.*
import me.ingxin.android.router.annotaions.route.IInterceptorWarehouse
import me.ingxin.android.router.annotaions.route.InterceptorMeta
import javax.annotation.processing.RoundEnvironment
import javax.lang.model.element.PackageElement


/**
 * Created by ingxin on 2022/4/15
 */
class InterceptorAppProcessor(processorUtil: ProcessorUtil, logger: Logger) :
    BaseProcessor(processorUtil, logger) {

    override fun getSupportedAnnotationTypes(): MutableSet<String> {
        return HashSet<String>().apply { add(App::class.java.name) }
    }

    fun checkApp(roundEnv: RoundEnvironment): String? =
        processorUtil.checkApp("InterceptorAppProcessor", roundEnv, logger)

    fun process(appOwner: String, list: List<LInterceptor>?) {
        //检测是否重复生成
        val warehouse = processorUtil.env.elementUtils
            .getTypeElement("${INTERCEPTOR_WAREHOUSE_PACKAGE_NAME}.${INTERCEPTOR_WAREHOUSE_CLASS_NAME}")
        if (warehouse != null) {
            val creator = warehouse.getAnnotation(LExtInfo::class.java)?.creator
            if (appOwner != creator) {
                logger.throwException("Duplicate annotation [@${App::class.java.simpleName}] found in class [$appOwner] and class [$creator]")
            }
        }

        val res = ArrayList<LInterceptor>()
        if (list?.isNotEmpty() == true) {
            res.addAll(list)
        }

        val interceptorPackage =
            processorUtil.env.elementUtils.getPackageElement(INTERCEPTOR_INDEX_PACKAGE_NAME)
        val allList = if (interceptorPackage != null) {
            getAll(interceptorPackage, res)
        } else {
            res
        }

        //按照priority排序，priority属性越大优先级越高,排序越前
        allList.sortWith { a, b -> b.priority - a.priority }

        //成员变量
        val property = PropertySpec.builder(
            "interceptors",
            ArrayList::class.asClassName()
                .parameterizedBy(InterceptorMeta::class.asClassName()),
            KModifier.PRIVATE
        )
            .initializer("%T()", ArrayList::class)
            .build()

        //init 代码块,用“·”声明不换行空格
        val ibb = CodeBlock.builder()
        allList.forEach {
            val lastIndex = it.destination.lastIndexOf(".")
            val classPackage = it.destination.substring(0, lastIndex)
            val className =
                it.destination.substring(lastIndex + 1, it.destination.length)
            val clazz = ClassName(classPackage, className)

            ibb.add(
                "interceptors.add(%T(\"${it.name}\",·%T::class.java,·${it.global},·${it.priority}))",
                InterceptorMeta::class, clazz
            )
            ibb.add("\n")
        }

        val funcSpec = FunSpec.builder("getInterceptorList")
            .addModifiers(KModifier.OVERRIDE)
            .returns(
                ArrayList::class.asClassName()
                    .parameterizedBy(
                        InterceptorMeta::class.asClassName()
                    )
            )
            .addStatement("return interceptors")
            .build()


        //增加构建信息
        val annotationSpec = AnnotationSpec.builder(LExtInfo::class)
            .addMember(
                CodeBlock.builder()
                    .add("""creator·=·"$appOwner"""").build()
            )
            .build()

        val classSpec = TypeSpec.classBuilder(INTERCEPTOR_WAREHOUSE_CLASS_NAME)
            .addProperty(property)
            .addAnnotation(annotationSpec)
            .addInitializerBlock(ibb.build())
            .addSuperinterface(IInterceptorWarehouse::class)
            .addFunction(funcSpec)
            .build()

        processorUtil.writeClass(INTERCEPTOR_WAREHOUSE_PACKAGE_NAME, classSpec)

    }

    private fun getAll(
        packageElement: PackageElement,
        list: MutableList<LInterceptor>
    ): MutableList<LInterceptor> {
        val tempMap = HashMap<String, LInterceptor>()
        list.forEach { tempMap[it.name] = it }
        for (element in packageElement.enclosedElements) {
            val annotation = element.getAnnotation(LInterceptorIndex::class.java) ?: continue
            for (item in annotation.interceptor) {
                val className = item.destination
                val name = item.name
                if (tempMap[name] != null) {
                    if (tempMap[name]?.destination == className) {
                        logger.warning("a annotation [@${App::class.java.simpleName}] was added, skip interceptor")
                        continue
                    }
                    logger.throwException("Duplicate interceptor name [$name] found in class [${tempMap[name]?.destination}] and class [$className]")
                }
                list.add(item)
                tempMap[item.destination] = item
            }
        }
        tempMap.clear()
        return list
    }


}